iT邦幫忙

2026 iThome 鐵人賽

DAY 14
0

中斷(interrupt)指的是讓 CPU 暫停手上的工作,先處理優先等級更高的項目,而中斷時期的工作都由「中斷服務常式(Interrupt Service Routine, ISR)」程式處理。

中斷服務常式 ISR

ISR 的寫法必須簡單、快速,而且因為 ISR 可能在任何時刻又被打斷(例如遇到優先程度更高的中斷要處理),必須要「可重入(reentrant)」。

所謂「可重入」指的是要可以在任何時刻被中斷,後面再回來繼續執行時依然不能出錯,而要達到可重入性質,ISR 不能調用外部共用資源,以避免造成競爭危害等混亂狀況。

為避免調用外部資源,ISR 的寫法有以下規範:

  1. 不能有回傳值(不能有輸出)
  2. 不能有參數(不能有輸入)
  3. 不應該有複雜的運算
  4. 不應該使用外部函式庫的方法

所以就下列範例來說:

__interrupt double compute_area(double radius) {

double area = PI * radius * radius;
printf(“nArea = %f”, area);

return area;
}

就是非常不好的例子,因為:

  1. 回傳型別是 double,應該要是 void 才對,所以 return area 也是錯的,因為 ISR 不應該有任何回傳值。
  2. 吃了 double radius 為參數,ISR 不應該有參數傳入。
  3. 進行複雜的浮點數運算,ISR 的運算應該要簡單。
  4. 使用 printf(),這個會用到外部的 <stdio> 函式庫。

假設真的要計算圓面積,則應該留到主程式處理,如下:

#define PI 3.14159

volatile int flag = 0; // 設定旗標;volatile 意義請參考 Day 11 文章

// 正確的 ISR 寫法
__interrupt void my_isr(void) {
    flag = 1; // ISR 只處理旗標
}

int main() {
    while (1) {
        if (flag) {  // 主程式以 ISR 控制的旗標判斷何時展開複雜運算
            // 複雜的運算留到主程式寫
            double area = PI * 2.0 * 2.0;
            printf("Area = %f\n", area);
            flag = 0;
        }
    }
    return 0;
}

真實世界的 ISR 範例

上述是用 C 語言表示的 ISR 概念程式碼,但真正的 ISR 寫法會因微控制器(Microcontroller Unit, MCU)開發環境而異,例如 Arduino 中,官方文件提及的 ISR 寫法如下:

const byte ledPin = 13;
const byte interruptPin = 2;  // input pin that the interruption will be attached to
volatile byte state = LOW;  // variable that will be updated in the ISR

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE);
}

void loop() {
  digitalWrite(ledPin, state);
}

void blink() {
  state = !state;
}

這當中的:

void blink() {
  state = !state;
}

就是 ISR,表示中斷發生時,要切換 state 狀態,是不是超級簡短又乾脆?

至於其他的程式碼在做什麼,老實說寫作的當下我也不懂,如果之後有要寫關於 Arduino 的學習筆記,再來好好理解。

參考資料

  1. A ‘C’ Test: The 0x10 Best Questions for Would-be Embedded Programmers
  2. Interrupt In Operating System (GeeksforGeeks)
  3. 17.2 Writing an Interrupt Service Routine(Online Docs - Microchip Technology)
  4. attachInterrupt() (Arduino Docs)

上一篇
Day 13 - Lambda 表達式
下一篇
Day 15:無窮迴圈
系列文
韌體工程師的不只 0x10 個問題19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言